﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.IO;

namespace Ession
{
    public class Pop3Helper
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="server"></param>
        /// <param name="port"></param>
        /// <param name="user"></param>
        /// <param name="pwd"></param>
        public Pop3Helper(string server, int port, string user, string pwd)
        {
            _pop3server = server;
            _port = port;
            _user = user;
            _pwd = pwd;
        }
        public byte[] _charData;
        public string _CRLF = "\r\n";
        public string _data;
        public NetworkStream _netStream;
        public StreamReader _reader;

        public TcpClient _server;
        public int MailCount = -1;
        public string UIDS = "";
        private string _log;
        string _pop3server;
        int _port;
        string _pwd;
        string _user;
        public string LogMSG
        {
            get { return _log; }
        }
        /// <summary>
        /// close connection
        /// </summary>
        public void Close()
        {

            _data = "QUIT" + _CRLF;
            _charData = System.Text.Encoding.ASCII.GetBytes(_data.ToCharArray());
            _netStream.Write(_charData, 0, _charData.Length);

            //close 
            _netStream.Close();
            _reader.Close();
        }
        /// <summary>
        /// connect
        /// </summary>
        public void Connect()
        {
            //create a tcp connection
            _server = new TcpClient(_pop3server, _port);

            //prepare 
            _netStream = _server.GetStream();
            _reader = new StreamReader(_server.GetStream());
            if (!CheckResult(_reader.ReadLine()))
                throw new Exception("Connect Error");

            //login
            _data = "USER " + this._user + _CRLF;
            _charData = System.Text.Encoding.ASCII.GetBytes(_data.ToCharArray());
            _netStream.Write(_charData, 0, _charData.Length);
            if (!CheckResult(_reader.ReadLine()))
                throw new Exception("User Error");

            _data = "PASS " + this._pwd + _CRLF;
            _charData = System.Text.Encoding.ASCII.GetBytes(_data.ToCharArray());
            _netStream.Write(_charData, 0, _charData.Length);
            if (!CheckResult(_reader.ReadLine()))
                throw new Exception("Pass Error");

        }
    
        public static string DecodeFromQuotedPrintable(string _ToDecode)
        {           
            char[] chars = _ToDecode.ToCharArray();

            byte[] bytes = new byte[chars.Length];

            int bytesCount = 0;

            for (int i = 0; i < chars.Length; i++)
            {
                 if (chars[i] == '=')
                {
                    bytes[bytesCount++] = System.Convert.ToByte(int.Parse(chars[i + 1].ToString() + chars[i + 2].ToString(), System.Globalization.NumberStyles.HexNumber));

                    i += 2;
                }
                else
                {
                    bytes[bytesCount++] = System.Convert.ToByte(chars[i]);
                }
            }
            return System.Text.Encoding.Default.GetString(bytes, 0, bytesCount); 
          //  return System.Text.Encoding.UTF8.GetString(bytes, 0, bytesCount);
        }
        public void DeleteMail(int id)
        {
            _data = "DELE" + id + _CRLF;
            _charData = System.Text.Encoding.ASCII.GetBytes(_data.ToCharArray());
            _netStream.Write(_charData, 0, _charData.Length);
            if (!CheckResult(_reader.ReadLine()))
                throw new Exception("Delete Error");

        }
        public static string getDatePartion(string MailHeader)
        {
            int i = MailHeader.IndexOf("Date:");
            int j = MailHeader.IndexOf("\r\n", i);

            return MailHeader.Substring(i + 6, j - i - 6);


        }
        //获取发信人邮箱地址字段
        public static string getFromPartion(string MailHeader)
        {
            int i = MailHeader.IndexOf("From:");
            i = MailHeader.IndexOf("<", i);

            int j = MailHeader.IndexOf(">", i);


            return MailHeader.Substring(i + 1, j - i - 1);

        }

        public string GetMail(int id)
        {
            string line;
            StringBuilder content = new StringBuilder();
            try
            {
                //get by id
                _data = "RETR " + id + _CRLF;
                _charData = System.Text.Encoding.ASCII.GetBytes(_data.ToCharArray());
                _netStream.Write(_charData, 0, _charData.Length);
                line = _reader.ReadLine();

                if (CheckResult(line))
                {
                    while (line != ".")
                    {
                        if (line != ".")
                        {
                            content.AppendLine(line);
                        }
                        line = _reader.ReadLine();


                    }
                    return content.ToString();
                }
                else
                {
                    return "";
                }

            }

            catch (Exception err)
            {
                Log(err.Message);
                return "";
            }
        }
        /// <summary>
        /// get message Numbers
        /// </summary>
        /// <returns></returns>
        public int GetMailCount()
        {
            try
            {
                _data = "STAT" + _CRLF;
                _charData = System.Text.Encoding.ASCII.GetBytes(_data.ToCharArray());
                _netStream.Write(_charData, 0, _charData.Length);
                string resp = _reader.ReadLine();
                string[] tokens = resp.Split(new char[] { ' ' });
                this.MailCount = Convert.ToInt32(tokens[1]);
                return MailCount;
            }
            catch (Exception ex)
            {
                return 0;
            }
        }

        //To be Modified
        public string GetMailHeader(int id)
        {
            string line;
            StringBuilder content = new StringBuilder();
            try
            {
                //get by id
                _data = "RETR " + id + _CRLF;
                _charData = System.Text.Encoding.ASCII.GetBytes(_data.ToCharArray());
                _netStream.Write(_charData, 0, _charData.Length);
                line = _reader.ReadLine();

                if (CheckResult(line))
                {
                    while (line != ".")
                    {
                        if (line != ".")
                        {
                            content.AppendLine(line);
                        }
                        line = _reader.ReadLine();


                    }
                    return content.ToString();
                }
                else
                {
                    return "";
                }

            }

            catch (Exception err)
            {
                Log(err.Message);
                return "";
            }
        }
        public string GetMailHeader(string MailContent)
        {
            try
            {
                int i = MailContent.IndexOf("boundary=\"");
                int j = MailContent.IndexOf("\"", i + 10);
                string bound = MailContent.Substring(i + 10, j - i - 10);
                i = MailContent.IndexOf(bound, j);  
                return MailContent.Substring(0, i);
            }
            catch (Exception ex)
            {
                throw ex;
            }          
          

         
        }
        public int GetMailIDFromUID(string UID)
        {
            try
            {
                if (this.UIDS == "")
                {
                    this.UIDS = GetMailUIDs();

                }
                int i = UIDS.IndexOf(UID);
                int j = 0;
                if (i < 3)
                {
                    return 1;
                }

                j = UIDS.LastIndexOf("\r\n", i - 2, 7);
                if (j < 0)
                {
                    j = UIDS.LastIndexOf("\r\n", i - 4, 7);
                }
                return int.Parse(UIDS.Substring(j + 1, i - j - 1));


            }
            catch (Exception ex)
            {
                return 0;
            }
        }
        public string GetMailIDs()
        {
            try
            {
                _data = "LIST" + _CRLF;
                _charData = System.Text.Encoding.ASCII.GetBytes(_data.ToCharArray());
                _netStream.Write(_charData, 0, _charData.Length);
                _netStream.Flush();
                string content = "", line;

                //if (line[0] != '-')
                //{
                //    //end with '.'

                line = _reader.ReadLine();
                while (line != ".")
                {
                    if (line != ".")
                    {
                        content += line + "\r\n";

                    }
                    line = _reader.ReadLine();


                }

                //}


                return content;
            }
            catch (Exception ex)
            {
                return "";
            }
        }
        public int getMailSizeFromHeader(string Header)
        {
            return int.Parse(Header.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries)[1]);
        }
        public string GetMailUIDFromID(int ID)
        {
            try
            {
                _data = "UIDL " + ID + _CRLF;
                _charData = System.Text.Encoding.ASCII.GetBytes(_data.ToCharArray());
                _netStream.Write(_charData, 0, _charData.Length);
                _netStream.Flush();
                string line;


                line = _reader.ReadLine();


                string[] s = new string[] { " " };
                return (line.Split(s, StringSplitOptions.RemoveEmptyEntries))[2];
                //     return int.Parse(line.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries)[0]);
            }
            catch (Exception ex)
            {
                return "";
            }
        }
        public string GetMailUIDs()
        {
            try
            {
                _data = "UIDL" + _CRLF;
                _charData = System.Text.Encoding.ASCII.GetBytes(_data.ToCharArray());
                _netStream.Write(_charData, 0, _charData.Length);
                _netStream.Flush();
                string content = "", line;

                //if (line[0] != '-')
                //{
                //    //end with '.'
                line = _reader.ReadLine();
                if (line.IndexOf("OK") > -1)
                {
                    while (line != ".")
                    {

                        line = _reader.ReadLine();
                        if (line != ".")
                        {
                            content += line + "\r\n";

                        }

                    }
                    this.UIDS = content;
                    return content;
                }
                else
                {
                    this.UIDS = "";
                    return "";
                }


            }
            catch (Exception ex)
            {
                return "";
            }
        }
        public static string getSubjectPartion(string MailHeader)
        {
            try
            {
                int j = 0;
                int i = MailHeader.IndexOf("Subject:");


                j = MailHeader.IndexOf("\r\n", i);
                return MailHeader.Substring(i + 8, j - i - 8);


            }
            catch (Exception ex)
            {
                return "格式无法提取";
            }




        }
        public Pop3Mail ParseMailHeader(string MailHeader)
        {
            string From, Date, Subject;
            From = getFromPartion(MailHeader);
            Date = getDatePartion(MailHeader);
            Subject = getSubjectPartion(MailHeader);
            Pop3Mail pm = new Pop3Mail();
            pm.senddate = Date;
            pm.senderMail = From;
            pm.title = ParseSubject(Subject);
            return pm;

        }
        public static string ParseSubject(string src)
        {
            //=?gb18030?b?zfjS1zEyNsPit9HTytDCtLrQwrmmxNzHwM/Iv7Q=?=
            int i, j = 0;

            i = src.IndexOf("=?");
            if (i > -1)//包含=?
            {
                if (src.IndexOf("b?") > -1 || src.IndexOf("B?") > -1)//采用base64
                {
                    string[] sub = src.Split(new string[] { "?" }, StringSplitOptions.RemoveEmptyEntries);

                    string encoding = sub[1];

                    string realData = sub[3];

                    return Encoding.GetEncoding(encoding).GetString(Convert.FromBase64String(realData));
                }
                else if (src.IndexOf("Q?") > -1 || src.IndexOf("q?") > -1)//采用q
                {
                    string[] sub = src.Split(new string[] { "?" }, StringSplitOptions.RemoveEmptyEntries);

                    string encoding = sub[1];

                    string realData = sub[3];

                    return Pop3Helper.DecodeFromQuotedPrintable(encoding);
                }
               
                return src;               
            }
            else
            {
                return src;
            }




        }

        private bool CheckResult(string reply)
        {
            Log(reply);
            if (reply.IndexOf("+OK") > -1)
                return true;
            else
                return false;
        }
        private void Log(string msg)
        {
            _log += msg + "\r\n";
        }
    }

    public class Pop3Mail
    {
        public string uid, title,
        senderMail,
        content,
        senderName,
        senddate;


    }

}
